home *** CD-ROM | disk | FTP | other *** search
/ The World's Largest Collection of Windows Software / The World's Largest Collection of Windows Software - Disc 1.iso / connect / _j2 / wsmtpd16 / debwsmtp.c < prev    next >
C/C++ Source or Header  |  1993-10-09  |  46KB  |  1,681 lines

  1. /* WSMTPSrv.C - Windows SMTP Server
  2.    DEBWSMTP.C - Same as above, with copius debugging info.
  3.     - WinSock V1.1 required
  4.  
  5.    Author: Ian Blenke
  6.  
  7. Ian Blenke cannot be held responsible for damages, expressed or implied, for
  8. the use of this software. No commercial use can be made of this product
  9. without the consent of the author. No profit of any kind can be made on the
  10. sale or distribution of this program. If you wish to distribute this program
  11. with other samples of WinSock programming, you must first contact the author
  12. so that he can keep accurate records of its usage. If you write any programs
  13. based on this source code, you may not sell them for any profit without the
  14. written consent of the author. If you incorporate this source code into a
  15. public domain program, all the author requires is a notification that "part
  16. of the code was written by Ian Blenke" and some form of notification that
  17. his name was used in the public domain software distribution. This does not
  18. represent a contract on the part of the author. If any issues cannot clearly
  19. be resolved by reading this text, immediately contact the author.
  20.  
  21. I don't like such agreements, but in today's world of lawyers and lawbreakers
  22. I have little other choice. Enjoy!
  23. */
  24.  
  25. #include "WSMTPSrv.h"
  26.  
  27. /* DEBUGIT();
  28.     Purpose: To print debugging messages to the debugging window/console.
  29. */
  30. VOID DEBUGIT( LPSTR lpString)
  31. {
  32.  static char szErrors[256];
  33.  
  34.  wsprintf((LPSTR)szErrors, (LPSTR)"WSMTPD: %s\n\r", lpString);
  35.  OutputDebugString( (LPSTR)szErrors );
  36. }
  37.  
  38. /* WinMain();
  39.     Purpose: The entry point for our app.
  40. */
  41. UINT PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  42.                     LPSTR lpszCmdLine, int nCmdShow)
  43. {
  44.  MSG        msg;
  45.  WORD       wVersionRequested;
  46.  WSADATA    wsaData;
  47.  DLGPROC    dlgProc;
  48.  WNDCLASS   wndclass;
  49.  HICON      hIcon;
  50.  
  51.  hInst=hInstance;
  52.  lstrcpy((LPSTR)szAppName, (LPSTR)APP_NAME);
  53.  
  54.  DEBUGIT("WinMain() Begin");
  55.  
  56.  if(hPrevInstance)
  57.  {
  58.   smtpError(IDS_PREV_INSTANCE);
  59.   return(NULL);
  60.  }
  61.  
  62.  wVersionRequested=WSVERSION;
  63.  if(WSAStartup(wVersionRequested, (LPWSADATA)&wsaData))
  64.  {
  65.   smtpError(IDS_NO_WINSOCK);
  66.   return(NULL);
  67.  }
  68.  if((LOBYTE(wsaData.wVersion)!=1) ||
  69.     (HIBYTE(wsaData.wVersion)!=1))
  70.  {
  71.   smtpError(IDS_BAD_VERSION);
  72.   WSACleanup();
  73.   DEBUGIT("WinSock version is not v1.1");
  74.   return(NULL);
  75.  }
  76.  
  77.  #ifdef USE_3D
  78.   Ctl3dRegister(hInst);
  79.   Ctl3dAutoSubclass(hInst);
  80.  #endif /*USE_3D*/
  81.  
  82.  
  83.  dlgProc=(DLGPROC)MakeProcInstance((FARPROC)DlgProc, hInst);
  84.  hWndDlg=CreateDialog(hInst, (LPSTR)dlgWSMTPSRV,
  85.               GetDesktopWindow(), dlgProc);
  86.  
  87.  if(!hWndDlg)
  88.  {
  89.   smtpError(IDS_SMTP_INIT);
  90. #ifdef USE_3D
  91.   Ctl3dUnregister(hInst);
  92. #endif // USE_3D
  93.   WSACleanup();
  94.   DEBUGIT("Modeless dialog window could not be opened");
  95.   return(NULL);
  96.  }
  97.  
  98.  hIcon=LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICONEMPTY));
  99.  
  100.  if(hIcon != NULL)
  101.  {
  102.   SetProp(hWndDlg, "icon", hIcon);
  103.  }
  104.  else DEBUGIT("IDI_ICONEMPTY Resource not found");
  105.  
  106.  SetClassWord(hWndDlg, GCW_HICON, NULL);
  107.  
  108.  ShowWindow(hWndDlg, nCmdShow);
  109.  
  110.  DEBUGIT("Starting smtpInit");
  111.  
  112.  if(smtpInit(INI_FILE))
  113.  {
  114.   DestroyWindow(hWndDlg);
  115. //  smtpError(IDS_SMTP_INIT);
  116. #ifdef USE_3D
  117.   Ctl3dUnregister(hInst);
  118. #endif /* USE_3D */
  119.   WSACleanup();
  120.   DEBUGIT("Daemon initialization error");
  121.   return(NULL);
  122.  }
  123.  
  124.  while(GetMessage(&msg, NULL, 0, 0))
  125.  {
  126.   if(!IsDialogMessage(hWndDlg, &msg))
  127.   {
  128.    TranslateMessage(&msg);
  129.    DispatchMessage(&msg);
  130.   }
  131.  }
  132.  
  133. #ifdef USE_3D
  134.  Ctl3dUnregister(hInst);
  135. #endif
  136.  
  137.   WSACleanup();
  138.  
  139.   DEBUGIT("WinMain() End");
  140.  
  141.   return msg.wParam;
  142. } /* WinMain */
  143.  
  144.  
  145. /* LRESULT CALLBACK DlgProc(HWND, UINT, WPARAM);
  146.     Purpose: To handle the main dialog user intervention.
  147.     Given/Returns: Standard Dialog procedure
  148. */
  149. LRESULT CALLBACK DlgProc(HWND hWnd, UINT Msg, WPARAM wParam,
  150.                       LPARAM lParam)
  151. {
  152.  HICON hIcon;
  153.  
  154.  switch(Msg)
  155.  {
  156.   case WM_INITDIALOG:
  157.     {
  158.      if(iLogLevel==LOG_LOW)
  159.      {
  160.       CheckRadioButton(hWnd, IDR_NORMAL, IDR_DEBUG,
  161.                        IDR_NORMAL);
  162.      }
  163.      else
  164.      {
  165.       CheckRadioButton(hWnd, IDR_NORMAL, IDR_DEBUG,
  166.                        IDR_DEBUG);
  167.      }
  168.      SetDlgItemText(hWnd, IDE_PATH, (LPSTR)szLocalMailPath);
  169.      SetDlgItemText(hWnd, IDE_HOSTNAME, (LPSTR)szLocalHostName);
  170.      return(TRUE);
  171.     }
  172.     break;
  173.  
  174.   case WM_COMMAND:
  175.   {
  176.    switch(wParam)
  177.    {
  178.     case IDR_NORMAL:
  179.     {
  180.      iLogLevel=LOG_LOW;
  181.      return(TRUE);
  182.     }
  183.  
  184.     case IDR_DEBUG:
  185.     {
  186.      iLogLevel=LOG_HIGH;
  187.      return(TRUE);
  188.     }
  189.  
  190.     case IDB_PATH:
  191.     {
  192.      int iError;
  193.      DWORD dwError;
  194.  
  195.      if(iError=GetOpenFileName((OPENFILENAME FAR *)&ofnMailPath))
  196.      {
  197.       WritePrivateProfileString(SECTION_MAIN, ENTRY_MAILPATH,
  198.                          (LPSTR)szLocalMailPath,
  199.                          (LPSTR)INI_FILE);
  200.       SetDlgItemText(hWndDlg, IDE_PATH, (LPSTR)szLocalMailPath);
  201.      }
  202.      else
  203.      {          // Debugging
  204.       dwError=CommDlgExtendedError();
  205.      }
  206.      return(TRUE);
  207.     }
  208.    }
  209.    break;
  210.  
  211.     // All of this, for a changing Icon - Sheesh
  212.    case WM_PAINT:
  213.    {
  214.     if(IsIconic(hWndDlg))
  215.     {
  216.      PAINTSTRUCT ps;
  217.      HDC hDC;
  218.      DWORD dwOrg;
  219.      HICON hIcon = GetProp(hWndDlg, "icon");
  220.  
  221.      if(hIcon != NULL)
  222.      {
  223.       hDC=BeginPaint(hWndDlg, &ps);
  224.  
  225.       dwOrg = GetWindowOrg(hDC);
  226.       SendMessage(hWndDlg, WM_ICONERASEBKGND, hDC, 0L);
  227.       DrawIcon(hDC, LOWORD(dwOrg)+2, HIWORD(dwOrg)+2, hIcon);
  228.       EndPaint(hWndDlg, &ps);
  229.       return(TRUE);
  230.      }
  231.     }
  232.    }
  233.    break;
  234.  
  235.    case WM_ERASEBKGND:
  236.    {
  237.     if(IsIconic(hWndDlg)) return(TRUE);
  238.     else return(FALSE);
  239.    }
  240.  
  241.    case WM_CLOSE:
  242.    {
  243.     RemoveProp(hWndDlg, "icon");
  244.     netClose();
  245.     DestroyWindow(hWndDlg);
  246.     return(TRUE);
  247.    }
  248.    break;
  249.  
  250.    case WM_QUERYDRAGICON:
  251.    {
  252.     HICON hIcon;
  253.  
  254.     return(hIcon = GetProp(hWndDlg, "icon"));
  255.    }
  256.  
  257.    /* Periodically check for mail until user reads it */
  258.    case WM_TIMER:
  259.    {
  260.     if(!smtpMailCheck(szLocalMailPath))
  261.     {
  262.      KillTimer(hWndDlg, (UINT)wParam);
  263.      SetWindowText(hWndDlg, (LPSTR)STRING_NOMAIL);
  264.     }
  265.     else
  266.     {
  267.      SetWindowText(hWndDlg, (LPSTR)STRING_HAVEMAIL);
  268.     }
  269.     return(TRUE);
  270.    }
  271.    break;
  272.  
  273.    /* Don't let the user ReSize/Maximize the window! */
  274.    case WM_INITMENUPOPUP:
  275.    {
  276.     if(HIWORD(lParam))
  277.     {
  278.      HMENU hSystemMenu;
  279.  
  280.      hSystemMenu = GetSystemMenu(hWndDlg, FALSE);
  281.      EnableMenuItem(hSystemMenu, SC_SIZE, MF_GRAYED);
  282.      EnableMenuItem(hSystemMenu, SC_MAXIMIZE, MF_GRAYED);
  283.     }
  284.    }
  285.    break;
  286.  
  287.    case WM_DESTROY:
  288.    {
  289.     PostQuitMessage(0);
  290.     return(TRUE);
  291.    }
  292.    break;
  293.   }
  294.  }
  295.  return(FALSE);
  296. } /* dlgProc() */
  297.  
  298.  
  299. /* void smtpError(int);
  300.     Purpose: To print out a resource string with parameters
  301.     Given:   ResourceID of format string, and variable arguements.
  302.     Returns: Nothing.
  303. */
  304. void smtpError(int ResourceID, ...)
  305. {
  306.  char szString[MAXLINE];
  307.  char szBuffer[MAXLINE];
  308.  va_list vaArgs;
  309.  LPSTR lpArg1, lpArg2;
  310.  
  311.  va_start( vaArgs, ResourceID);
  312.  lpArg1 = va_arg( vaArgs, LPSTR);
  313.  lpArg2 = va_arg( vaArgs, LPSTR);
  314.  
  315.  if(IsIconic(hWndDlg))          // If in server mode, no modals!
  316.  {
  317.   smtpLog(LOG_HIGH | LOG_TIME, ResourceID, vaArgs);
  318.   return;
  319.  }
  320.  
  321.  if(!LoadString(hInst, ResourceID, (LPSTR)szString,
  322.                 MAXLINE))
  323.     return;
  324.  
  325.  wsprintf((LPSTR)szBuffer, (LPSTR)szString, lpArg1, lpArg2);
  326.  
  327.  DEBUGIT(szBuffer);
  328.  MessageBeep(MB_ICONEXCLAMATION);
  329.  MessageBox(NULL, (LPSTR)szBuffer, (LPSTR)szAppName,
  330.             MB_OK | MB_ICONEXCLAMATION);
  331.  return;
  332. } /* smtpError */
  333.  
  334.  
  335. /* void smtpLog(int, ...);
  336.     Purpose: To print an item in the "log" listbox.
  337.     Given:   Resource ID and variable args.
  338.     Returns: Nothing
  339. */
  340. void smtpLog(int iLevel, int ResourceID, ...)
  341. {
  342.  char szString[MAXLINE];
  343.  char szLine[MAXLINE];
  344.  char szTime[30];
  345.  LPSTR lpArg1, lpArg2;
  346.  va_list vaArgs;
  347.  DWORD dwCount;
  348.  
  349.  if((iLevel&(LOG_TIME-1))<iLogLevel) return;          // Only log what we want
  350.  
  351.  va_start( vaArgs, ResourceID);
  352.  
  353.  if(!LoadString(hInst, ResourceID, (LPSTR)szLine, MAXLINE))
  354.     return;
  355.  
  356.  lpArg1=va_arg(vaArgs, LPSTR);
  357.  lpArg2=va_arg(vaArgs, LPSTR);
  358.  
  359.  wsprintf((LPSTR)szString, (LPSTR)szLine, lpArg1, lpArg2);
  360.  
  361.  if(iLevel&LOG_TIME)
  362.  {
  363.   netGetTimeAndDate((LPSTR)szTime, sizeof(szTime));
  364.   wsprintf((LPSTR)szLine, "%s> %s", (LPSTR)szTime, (LPSTR)szString);
  365.  }
  366.  else
  367.  {
  368.   lstrcpy((LPSTR)szLine, (LPSTR)szString);
  369.  }
  370.  DEBUGIT(szLine);
  371.  SendDlgItemMessage(hWndDlg, IDL_LOG, LB_ADDSTRING, 0,
  372.                     (LPARAM)(LPCSTR)szLine);
  373.  
  374.  dwCount=SendDlgItemMessage(hWndDlg, IDL_LOG, LB_GETCOUNT, 0, 0l);
  375.  if(dwCount>MAXITEMS)
  376.  {
  377.   SendDlgItemMessage(hWndDlg, IDL_LOG, LB_RESETCONTENT, 0, 0l);
  378.   wsprintf((LPSTR)szLine, "%s> Reset Log - over %d lines", (LPSTR)szTime,
  379.            MAXITEMS);
  380.   DEBUGIT(szLine);
  381.   SendDlgItemMessage(hWndDlg, IDL_LOG, LB_ADDSTRING, 0,
  382.                     (LPARAM)(LPCSTR)szLine);
  383.  }
  384. } /* smtpLog */
  385.  
  386.  
  387. /* BOOL smtpInit(PSTR);
  388.     Purpose: To setup the SMTP protocol and structures.
  389.     Given:   A filename.
  390.     Returns: TRUE on error, FALSE if not.
  391. */
  392. BOOL smtpInit(PSTR pFilename)
  393. {
  394.  LPSTR lpString;
  395.  HANDLE hMenu;
  396.  
  397.  ofnMailPath.lStructSize=sizeof(ofnMailPath);
  398.  ofnMailPath.hwndOwner=hWndDlg;
  399.  ofnMailPath.hInstance=hInst;
  400.  szMailPathFilter[0]='\0';
  401.  LoadString(hInst, IDS_FILTER,
  402.             (LPSTR)szMailPathFilter, sizeof(szMailPathFilter));
  403.  ofnMailPath.lpstrFilter=(LPSTR)szMailPathFilter;
  404.  ofnMailPath.nFilterIndex=2;
  405.  ofnMailPath.lpstrCustomFilter=(LPSTR)NULL;
  406.  ofnMailPath.lpstrFile=(LPSTR)szLocalMailPath;
  407.  ofnMailPath.nMaxFile=sizeof(szLocalMailPath);
  408.  ofnMailPath.lpstrFileTitle=(LPSTR)NULL;
  409.  ofnMailPath.lpstrInitialDir=(LPSTR)NULL;
  410.  ofnMailPath.lpstrTitle=(LPSTR)szAppName;
  411.  ofnMailPath.Flags=OFN_CREATEPROMPT | OFN_NOREADONLYRETURN;
  412.  ofnMailPath.lpstrDefExt=(LPSTR)NULL;
  413.  
  414.     // Initialize network windows & such
  415.  if(netInit()) return(TRUE);
  416.  
  417.  iLogLevel=GetPrivateProfileInt(SECTION_MAIN, ENTRY_DEBUG,
  418.                                 LOG_HIGH, (LPSTR)pFilename);
  419.  GetPrivateProfileString(SECTION_MAIN, ENTRY_MAILPATH,
  420.                          (LPSTR)DEFAULTMAILFILE,
  421.                          (LPSTR)szLocalMailPath,
  422.                          sizeof(szLocalMailPath),
  423.                          (LPSTR)pFilename);
  424.  
  425.  if(iLogLevel==LOG_LOW)
  426.  {
  427.   CheckRadioButton(hWndDlg, IDR_NORMAL, IDR_DEBUG,
  428.                    IDR_NORMAL);
  429.  }
  430.  else
  431.  {
  432.   CheckRadioButton(hWndDlg, IDR_NORMAL, IDR_DEBUG,
  433.                    IDR_DEBUG);
  434.  }
  435.  SetDlgItemText(hWndDlg, IDE_PATH, (LPSTR)szLocalMailPath);
  436.  SetDlgItemText(hWndDlg, IDE_HOSTNAME, (LPSTR)szLocalHostName);
  437.  
  438.  return(FALSE);
  439. } /* smtpInit */
  440.  
  441.  
  442. /* BOOL smtpServer(LPSMTPCLIENT);
  443.     Purpose: To be the heart & soul of the SMTP
  444.              server.
  445.     Given:   pointer to the Client that was active.
  446.     Returns: FALSE
  447.     Notes:   This is the heart & soul of the beast.
  448. */
  449. BOOL smtpServer(LPSMTPCLIENT lpClient)
  450. {
  451.  static char szLine[MAXSNDBUFF];       // These are still holdovers
  452.  static char szPaddedLine[MAXSNDBUFF]; // They should be replaced
  453.  PSTR pLine;
  454.  int iDebug;
  455.  BOOL bCmdOk;
  456.  
  457.  if(!lpClient) return(TRUE);
  458.  
  459.  DEBUGIT("smtpServer() Begin");
  460.  
  461.     // 8BITMIME hack
  462.  if((lpClient->iExtendedFlags & ESMTP_8BITMIME) &&
  463.     (lpClient->iState == STATE_WAIT_FOR_DOT))
  464.  {
  465.   DEBUGIT("ESMTP_8BITMIME && STATE_WAIT_FOR_DOT");
  466.   while(clientReceiveBlock(lpClient, szLine, sizeof(szLine)))
  467.   {
  468.    if(lpClient->hfFile!=HFILE_ERROR)
  469.    {
  470.     iDebug=_lwrite(lpClient->hfFile,
  471.             (LPSTR)szLine, lstrlen((LPSTR)szLine));
  472.    }
  473.   } // While there is data
  474.  } // If in DATA state with 8BITMIME active.
  475.  
  476.     // This is a hack for when a client QUIT's.
  477.  bConnectionQuit=FALSE;
  478.  
  479.     // Get as many lines as are waiting
  480.  while(!bConnectionQuit &&
  481.        (clientReceiveLine(lpClient, szLine, sizeof(szLine)) >= 0))
  482.  {
  483.     // Treat them one at a time
  484.   switch(lpClient->iState)
  485.   { // Command mode?
  486.    case STATE_WAIT_FOR_COMMAND:
  487.    {
  488.     int iLoop;
  489.  
  490.     DEBUGIT("STATE_WAIT_FOR_COMMAND");
  491.     if(!(*szLine))
  492.     {
  493.      smtpSendMessage(lpClient, 500, MSG_UNKNOWN);
  494.      continue;  // CR, LF, or '\0' came across
  495.     }
  496.  
  497.     pLine=szLine;
  498.     while((*pLine!='\0')&&(*pLine!=' ')&&(*pLine!='\n'))
  499.             pLine++;
  500.     AnsiLower((LPSTR)szLine);
  501.     if(*pLine!='\0')
  502.     {
  503.      *(pLine++)='\0';
  504.     }
  505.         // szLine now holds the lowercase command
  506.         // pLine points to the remaining parameters
  507.     iLoop=0;
  508.     bCmdOk=FALSE;
  509.     while(smtpCodesTable[iLoop].SMTPCommand != NULL)
  510.     {
  511.      if(lstrcmp((LPSTR)smtpCodesTable[iLoop].SMTPCommand,
  512.                 (LPSTR)szLine)==0)
  513.      {
  514.       smtpParser(lpClient, smtpCodesTable[iLoop].SMTPCode, pLine);
  515.       bCmdOk=TRUE;
  516.       break;
  517.      }
  518.      iLoop++;
  519.     }
  520.     if(!bCmdOk) smtpSendMessage(lpClient, 500, MSG_UNKNOWN);
  521.    }
  522.    break;
  523.  
  524.     // Data mode?
  525.    case STATE_WAIT_FOR_DOT:
  526.    {
  527.     DEBUGIT("STATE_WAIT_FOR_DOT");
  528.     if((szLine[0]=='.')&&(szLine[1]=='\0'))
  529.     {
  530.      lpClient->iState=STATE_WAIT_FOR_COMMAND;
  531.      if(lpClient->hfFile!=HFILE_ERROR)
  532.      {
  533.              _lclose(lpClient->hfFile);
  534.      }
  535.      lpClient->hfFile=HFILE_ERROR;
  536.         // Handle MAIL/SAML/SOML as MAIL
  537.      if((lpClient->iMessageType==CMDMAIL)||
  538.         (lpClient->iMessageType==CMDSAML)||
  539.         (lpClient->iMessageType==CMDSOML))
  540.      {
  541.       smtpAppendToFile(lpClient, szLocalMailPath,
  542.                        lpClient->szFile);
  543.      }
  544.         // Handle SAML/SEND as SEND also
  545.      if((lpClient->iMessageType==CMDSAML)||
  546.         (lpClient->iMessageType==CMDSEND))
  547.      {
  548.       smtpDisplayFile(lpClient, lpClient->szFile);
  549.      }
  550.      smtpSendMessage(lpClient, 250, MSG_OK);
  551.      continue;
  552.     }
  553.     else if((szLine[0]=='.')&&(szLine[1]=='.'))
  554.     {   // Byte stuff it! Someone tried to send a '.' in their
  555.         // message. Only the first '.' is doubled.
  556.      lstrcpy((LPSTR)szPaddedLine, (LPSTR)(szLine+1));
  557.      lstrcpy((LPSTR)szLine, (LPSTR)szPaddedLine);
  558.     }
  559.         // All non '.' lines are stored.
  560.     if(lpClient->hfFile!=HFILE_ERROR)
  561.     {
  562.      wsprintf((LPSTR)szPaddedLine, "%s\r\n", (LPSTR)szLine);
  563.      iDebug=_lwrite(lpClient->hfFile,
  564.              (LPSTR)szPaddedLine, lstrlen((LPSTR)szPaddedLine));
  565.     }
  566.     continue;
  567.    } /* case(data mode)  */
  568.    break;
  569.   } /* switch(mode);     */
  570.   if(bConnectionQuit) break;
  571.  } /* while(lines exist);*/
  572.  DEBUGIT("smtpServer() End");
  573.  return(FALSE);
  574. } /* smtpServer() */
  575.  
  576.  
  577. /* BOOL smtpParser(LPSMTPCLIENT, int, LPSTR);
  578.     Purpose: The actual parser of the SMTP "language"
  579.     Given:   Client pointer, Token of command, and it's arguments
  580. */
  581. BOOL smtpParser(LPSMTPCLIENT lpClient, int iToken, LPSTR lpArgs)
  582. {
  583.  DEBUGIT("smtpParser() Begin");
  584.  switch(iToken)
  585.  {
  586.     // HELO - SMTP client is identifying itself
  587.   case CMDHELO:
  588.   {
  589.    DEBUGIT("CMDHELO Begin");
  590.    if(lstrcmpi(lpClient->szPeer, lpArgs) != 0)
  591.    {
  592.     if(lstrlen(lpArgs) == 0)
  593.         smtpSendMessage(lpClient, 250, MSG_WHOAREYOU_S_S,
  594.                     (LPSTR)szLocalHostName,
  595.                     lpClient->szPeer);
  596.     else
  597.         smtpSendMessage(lpClient, 250, MSG_WHOAREYOU_S_S_S,
  598.                     (LPSTR)szLocalHostName,
  599.                     lpClient->szPeer,
  600.                     lpArgs);
  601.    }
  602.    else
  603.    {
  604.     smtpSendMessage(lpClient, 250, MSG_HELLO_S_S,
  605.                     (LPSTR)szLocalHostName,
  606.                     lpArgs);
  607.    }
  608.    DEBUGIT("CMDHELO End");
  609.    return(FALSE);
  610.   }
  611.  
  612.     // EHLO - ESMTP client is identifying itself
  613.   case CMDEHLO:
  614.   {
  615.    DEBUGIT("CMDEHLO Begin");
  616.    if(lstrcmpi(lpClient->szPeer,
  617.                lpArgs) != 0)
  618.    {
  619.     if(lstrlen(lpArgs) == 0)
  620.         smtpSendMessage(lpClient, 250, MSG_HWOAREYOU_S_S,
  621.                     (LPSTR)szLocalHostName,
  622.                     lpClient->szPeer);
  623.     else
  624.         smtpSendMessage(lpClient, 250, MSG_HWOAREYOU_S_S_S,
  625.                     (LPSTR)szLocalHostName,
  626.                     lpClient->szPeer,
  627.                     lpArgs);
  628.    }
  629.    else
  630.    {
  631.     smtpSendMessage(lpClient, 250, MSG_EHLLO_S_S,
  632.                     (LPSTR)szLocalHostName,
  633.                     lpArgs);
  634.    }
  635.    lpClient->iExtendedFlags |= ESMTP_EHLO_USED;
  636.    DEBUGIT("CMDEHLO End");
  637.    return(FALSE);
  638.   }
  639.  
  640.     // Oh, joy.
  641.   case CMDSEND: // Send user a message to screen
  642.   case CMDSAML: // Send to screen AND store as mail
  643.   case CMDSOML: // Send to screen OR store as mail
  644.   case CMDMAIL: // Store as mail to user
  645.   {
  646.    LPSTR lpPtr;
  647.    LPSTR lpWalk;
  648.    LPSTR lpMark;
  649.    BOOL bSentReply = FALSE;
  650.  
  651.    DEBUGIT("CMDMAIL Begin");
  652.    lpClient->iMessageType=iToken;
  653.    if(lpClient->bHaveFrom)
  654.    {
  655.     smtpSendMessage(lpClient, 503, MSG_ALREADYSENDER);
  656.     return(FALSE);
  657.    }
  658.    else
  659.    {
  660.     if(*lpArgs=='\0') break;
  661.     if( ( lpPtr = smtpSkipWord( lpClient, lpArgs, (LPSTR)"from" )) != NULL )
  662.     {
  663.      lpClient->bHaveFrom=TRUE;
  664.         // No long name crashes!
  665.      if(lstrlen(lpPtr)>=sizeof(lpClient->szFrom))
  666.             lpPtr[sizeof(lpClient->szFrom)-1] = '\0';
  667.  
  668.         // 8BITMIME and other ESMTP hacks
  669.      if(lpClient->iExtendedFlags & ESMTP_EHLO_USED)
  670.      {
  671.         // Check for ESMTP commands after the Sender's address
  672.       lpWalk=lpPtr;
  673.       while((*lpWalk!='>') && *lpWalk ) lpWalk++;
  674.       if((*lpWalk)&&(*(lpWalk+1)))
  675.       {
  676.        if(*(++lpWalk)==' ')
  677.        {
  678.         while(*lpWalk==' ') *lpWalk++ = '\0';
  679.         lpMark=lpWalk;
  680.         while((*lpWalk!='=') && *lpWalk ) lpWalk++;
  681.         if(*lpWalk) *lpWalk++ = '\0';
  682.         if(lstrcmpi(lpMark, "BODY") == 0)
  683.         {
  684.          lpMark=lpWalk;
  685.          while((*lpWalk!=' ') && *lpWalk ) lpWalk++;
  686.          if(*lpWalk) *lpWalk++ = '\0';
  687.          if(lstrcmpi(lpMark, "8BITMIME") == 0)
  688.          {
  689.           lpClient->iExtendedFlags |= ESMTP_8BITMIME;
  690.           bSentReply=TRUE;
  691.           smtpSendMessage(lpClient, 250, MSG_SENDEROK_8BITMIME_S,
  692.                           (LPSTR)lpPtr);
  693.          } // if 8BITMIME found
  694.         } // if BODY= found
  695.        } // if address is followed by a space
  696.       } // if something was found after the address
  697.      } // if extended commands are in effect
  698.  
  699.      lstrcpy(lpClient->szFrom,
  700.              lpPtr);
  701.      if(!bSentReply) smtpSendMessage(lpClient, 250, MSG_SENDEROK_S,
  702.                                      lpPtr);
  703.      DEBUGIT("CMDMAIL End (Extended)");
  704.      return(FALSE);
  705.     }
  706.         // a 501 error was already sent
  707.     DEBUGIT("CMDMAIL End (Already Sender)");
  708.     return(FALSE);
  709.    }
  710.    DEBUGIT("CMDHELO End (Normal)");
  711.   } break;
  712.  
  713.     // RCPT - Client is identifying recipient's ID
  714.   case CMDRCPT:
  715.   {
  716.    LPSTR lpPtr;
  717.  
  718.    DEBUGIT("CMDRCPT Begin");
  719.    if( *lpArgs == '\0' ) break;
  720.    if( ( lpPtr = smtpSkipWord( lpClient, lpArgs, (LPSTR)"to" )) != NULL )
  721.    {
  722.         // No long name crashes!
  723.     if(lstrlen(lpPtr)>=sizeof(lpClient->szTo))
  724.             lpPtr[sizeof(lpClient->szTo)-1] = '\0';
  725.     lstrcpy(lpClient->szTo,
  726.             lpPtr);
  727.     smtpSendMessage( lpClient, 250, MSG_RECIPIENTOK_S,
  728.                      lpPtr );
  729.     DEBUGIT("CMDRCPT End (Recipient ok)");
  730.     return(FALSE);
  731.    }
  732.        // A 501 error was already sent
  733.    DEBUGIT("CMDRCPT End (???)");
  734.    return(FALSE);
  735.   } break;
  736.  
  737.     // DATA - Client is sending actual mail message
  738.   case CMDDATA:
  739.   {
  740.    HFILE hfFile;
  741.    char szFile[MAXFILENAME];
  742.    OFSTRUCT ofOpenFileStruct;
  743.  
  744.    DEBUGIT("CMDDATA Begin");
  745.    if(!lpClient->bHaveFrom)
  746.    {
  747.     smtpSendMessage(lpClient, 503, MSG_NEEDMAIL);
  748.     DEBUGIT("CMDDATA End (Need mail?)");
  749.     return(FALSE);
  750.    }
  751.         // Open a temporary file
  752.    GetTempFileName(0, (LPSTR)STRING_PREFIX, 0, (LPSTR)szFile);
  753.    hfFile=OpenFile((LPSTR)szFile, (OFSTRUCT FAR *)&ofOpenFileStruct,
  754.                     OF_CREATE | OF_WRITE | OF_SHARE_EXCLUSIVE);
  755.  
  756.    if(hfFile==HFILE_ERROR)
  757.    {
  758.     smtpSendMessage(lpClient, 503, MSG_NOTEMP);
  759.     DEBUGIT("CMDDATA End (No temporary file)");
  760.     return(FALSE);
  761.    }
  762.         // Ok, everything is ready to start the message.
  763.    lpClient->iState=STATE_WAIT_FOR_DOT;
  764.    lpClient->hfFile=hfFile;
  765.    lstrcpy(lpClient->szFile,
  766.            (LPSTR)szFile);
  767.  
  768.    smtpMakeHeader(lpClient, hfFile, lpClient->szPeer,
  769.                   lpClient->szFrom,
  770.                   lpClient->szTo);
  771.  
  772.    if(lpClient->iExtendedFlags & ESMTP_8BITMIME)
  773.      smtpSendMessage(lpClient, 354, MSG_SEND8BITMIME);
  774.    else
  775.      smtpSendMessage(lpClient, 354, MSG_SENDDATA);
  776.  
  777.    DEBUGIT("CMDDATA End");
  778.    return(FALSE);
  779.   }
  780.  
  781.   case CMDRSET:
  782.   {
  783.    DEBUGIT("CMDRSET Begin");
  784.    lpClient->iState=STATE_WAIT_FOR_COMMAND;
  785.    lpClient->iExtendedFlags=ESMTP_NONE;
  786.    lpClient->bHaveFrom=FALSE;
  787.    lpClient->szFrom[0]='\0';
  788.    lpClient->szTo[0]='\0';
  789.    smtpSendMessage(lpClient, 250, MSG_RESET);
  790.    DEBUGIT("CMDRSET End");
  791.    return(FALSE);
  792.   }
  793.  
  794.   case CMDVRFY:
  795.   {
  796.    DEBUGIT("CMDVRFY Begin");
  797.    smtpSendMessage(lpClient, 250, MSG_IDONTDOTHATYET);
  798.    DEBUGIT("CMDVRFY Begin");
  799.    return(FALSE);
  800.   }
  801.  
  802.   case CMDHELP:
  803.   {
  804.    DEBUGIT("CMDHELP Begin");
  805.    if(*lpArgs=='\0')
  806.    {
  807.     smtpSendHelp(lpClient, NULL);
  808.    }
  809.    else smtpSendHelp(lpClient, lpArgs);
  810.    DEBUGIT("CMDHELP End");
  811.    return(FALSE);
  812.   } break;
  813.  
  814.   case CMDNOOP:
  815.   {
  816.    DEBUGIT("CMDNOOP Begin");
  817.    smtpSendMessage(lpClient, 200, MSG_OK);
  818.    DEBUGIT("CMDNOOP Begin");
  819.    return(FALSE);
  820.   }
  821.  
  822.   case CMDQUIT:
  823.   {
  824.    DEBUGIT("CMDQUIT Begin");
  825.    smtpSendMessage(lpClient, 221, MSG_GOODBYE_S,
  826.                    (LPSTR)szLocalHostName);
  827.    smtpDestroyClient(lpClient);
  828.    bConnectionQuit=TRUE;
  829.    DEBUGIT("CMDQUIT End");
  830.    return(FALSE);
  831.   }
  832.  
  833.   case CMDVERB:
  834.   {
  835.    DEBUGIT("CMDVERB Begin");
  836.    smtpSendMessage(lpClient, 200, MSG_VERBOSEMODE);
  837.    DEBUGIT("CMDVERB End");
  838.    return(FALSE);
  839.   }
  840.  
  841.   case CMDONEX:
  842.   {
  843.    DEBUGIT("CMDONEX Begin");
  844.    smtpSendMessage(lpClient, 200, MSG_ONETRANSACTION);
  845.    DEBUGIT("CMDONEX End");
  846.    return(FALSE);
  847.   }
  848.  
  849.   case CMDTICK:
  850.   {
  851.    DEBUGIT("CMDTICK Begin");
  852.    smtpSendMessage(lpClient, 250, MSG_OK);
  853.    DEBUGIT("CMDTICK End");
  854.    return(FALSE);
  855.   }
  856.  
  857.   case CMDXWIN3:
  858.   {
  859.    DEBUGIT("CMDXWIN3 Begin");
  860.    smtpSendMessage(lpClient, 250, MSG_WIN3OK);
  861.    DEBUGIT("CMDXWIN3 End");
  862.    return(FALSE);
  863.   }
  864.  
  865.   case CMDDBGQSHOW:
  866.   {
  867.    DEBUGIT("CMDDBGQSHOW Begin");
  868.    smtpSendMessage(lpClient, 200, MSG_SHOWQ);
  869.    DEBUGIT("CMDDBGQSHOW End");
  870.    return(FALSE);
  871.   }
  872.  
  873.   case CMDDBGDEBUG:
  874.   {
  875.    DEBUGIT("CMDDBGDEBUG Begin");
  876.    smtpSendMessage(lpClient, 200, MSG_DEBUGSET);
  877.    DEBUGIT("CMDDBGDEBUG End");
  878.    return(FALSE);
  879.   }
  880.  
  881.   case CMDMULT:
  882.   {
  883.    DEBUGIT("CMDMULT Begin");
  884.    smtpSendMessage(lpClient, 250, MSG_OK);
  885.    DEBUGIT("CMDMULT End");
  886.    return(FALSE);
  887.   }
  888.  
  889.   case CMDERROR:
  890.     DEBUGIT("CMDERROR");
  891.   default:
  892.   break;
  893.  }
  894.  smtpSendMessage(lpClient, 500, MSG_UNKNOWN);
  895.  DEBUGIT("smtpParser() End");
  896.  return(FALSE);
  897. } /* smtpParser() */
  898.  
  899.  
  900. /* void smtpMakeHeader(LPSMTPCLIENT, HFILE, LPSTR, LPSTR, LPSTR);
  901.     Purpose: To create the "header" portion of the mail
  902.              file.
  903.     Given:   Client pointer, Open (and valid) file handle,
  904.              Peer name, From and To strings.
  905.     Returns: Nothing.
  906. */
  907. void smtpMakeHeader(LPSMTPCLIENT lpClient, HFILE hfFile, LPSTR lpPeer,
  908.                     LPSTR lpFrom, LPSTR lpTo)
  909. {
  910.  int iSize;
  911.  char szTime[30];
  912.  char szBuffer[MAXLINE];
  913.  LPSOCKADDR_IN lpsaHostAddr;
  914.  
  915.  DEBUGIT("smtpMakeHeader() Begin");
  916.  lpsaHostAddr=(LPSOCKADDR_IN)&(lpClient->saPeer);
  917.  
  918.  netGetTimeAndDate((LPSTR)szTime, sizeof(szTime));
  919.  
  920.  iSize=wsprintf((LPSTR)szBuffer, "\r\nFrom %s %s\r\n",
  921.                 lpFrom, (LPSTR)szTime);
  922.  _lwrite(hfFile, (LPSTR)szBuffer, iSize);
  923.  
  924.  iSize=wsprintf((LPSTR)szBuffer, "X-Envelope-To: %s\r\n",
  925.                 lpTo);
  926.  _lwrite(hfFile, szBuffer, iSize);
  927.  
  928.  iSize=wsprintf((LPSTR)szBuffer, "Return-Path: %s\r\n",
  929.                 lpFrom);
  930.  _lwrite(hfFile, (LPSTR)szBuffer, iSize);
  931.  
  932.  if(lpClient->iExtendedFlags & ESMTP_8BITMIME)
  933.  {
  934.   iSize=wsprintf((LPSTR)szBuffer,
  935.        "Received: from %s [%s] by %s (1.0/WINSMTPSRV/8BITMIME)\r\n",
  936.                 lpPeer,
  937.                 inet_ntoa(lpsaHostAddr->sin_addr),
  938. /*  inet_ntoa() and [%s] or this and [%d.%d.%d.%d], take your pick
  939.                 lpsaHostAddr->sin_addr.S_un.S_un_b.s_b1,
  940.                 lpsaHostAddr->sin_addr.S_un.S_un_b.s_b2,
  941.                 lpsaHostAddr->sin_addr.S_un.S_un_b.s_b3,
  942.                 lpsaHostAddr->sin_addr.S_un.S_un_b.s_b4,
  943. */
  944.                 (LPSTR)szLocalHostName);
  945.  }
  946.  else
  947.  {
  948.   iSize=wsprintf((LPSTR)szBuffer,
  949.        "Received: from %s [%s] by %s (1.61/WINSMTPSRV)\r\n",
  950.                 lpPeer,
  951.                 inet_ntoa(lpsaHostAddr->sin_addr),
  952.                 (LPSTR)szLocalHostName);
  953.  }
  954.  
  955.  _lwrite(hfFile, (LPSTR)szBuffer, iSize);
  956.  
  957.      // Log incoming to/from
  958.  wsprintf((LPSTR)szBuffer, "Message from: %s  to: %s",
  959.           lpFrom, lpTo);
  960.  SendDlgItemMessage(hWndDlg, IDL_LOG, LB_ADDSTRING, 0,
  961.                      (LPARAM)(LPCSTR)szBuffer);
  962.  DEBUGIT("smtpMakeHeader() End");
  963.  return;
  964. } /* smtpMakeHeader */
  965.  
  966.  
  967. /* void smtpSendHelp(LPSMTPCLIENT, LPSTR);
  968.     Purpose: To give the remote user help (not batch, obviously)
  969.     Given:   Client Index, Topic
  970.     Returns: Nothing.
  971. */
  972. void smtpSendHelp(LPSMTPCLIENT lpClient,LPSTR lpTopic)
  973. {
  974.  LPSTR lpLine;
  975.  int  iLoop;
  976.  WORD wTopic;
  977.  char szBuffer[MAXSNDBUFF];
  978.  
  979.  DEBUGIT("smtpSendHelp() Begin");
  980.  if(lpTopic!=NULL)
  981.  {
  982.   lpLine=lpTopic;
  983.  
  984.   // pLine points to the HELP parameters
  985.   iLoop=0;
  986.   wTopic=CMDHELP;
  987.   while(smtpCodesTable[iLoop].SMTPCommand != NULL)
  988.   {
  989.    if(lstrcmp((LPSTR)smtpCodesTable[iLoop].SMTPCommand,
  990.               lpLine)==0)
  991.    {
  992.     wTopic=(WORD)smtpCodesTable[iLoop].SMTPCode;
  993.     break;
  994.    }
  995.    iLoop++;
  996.   }
  997.  }
  998.  else wTopic=CMDHELP;
  999.  
  1000.  smtpSendMessage(lpClient, 214, wTopic);
  1001.  
  1002.     // Kludge
  1003.  if(lpTopic==NULL)
  1004.  {
  1005.   lstrcpy((LPSTR)szBuffer, "HELP");
  1006.  }
  1007.  else
  1008.  {
  1009.   lstrcpy((LPSTR)szBuffer, (LPSTR)smtpCodesTable[iLoop].SMTPCommand);
  1010.   AnsiUpper((LPSTR)szBuffer);
  1011.  }
  1012.  
  1013.  smtpSendMessage(lpClient, 214, MSG_END_HELP_S, (LPSTR)szBuffer);
  1014.  DEBUGIT("smtpSendHelp() End");
  1015.  return;
  1016. } /* smtpSendHelp */
  1017.  
  1018.  
  1019. /* LPSTR smtpSkipWord(LPSMTPCLIENT, LPSTR, LPSTR);
  1020.     Purpose: To skip over words not neccisary on an SMTP line.
  1021.     Given:   Client pointer, string to examine, word to skip
  1022.     Returns: NULL if error, rest of line if not
  1023. */
  1024. LPSTR smtpSkipWord(LPSMTPCLIENT lpClient, LPSTR lpString, LPSTR lpWord)
  1025. {
  1026.  LPSTR lpTemp;
  1027.  
  1028.  DEBUGIT("smtpSkipWord() Begin");
  1029.  while((*lpString==' ')||(*lpString=='\t'))  lpString++;
  1030.  lpTemp=lpString;
  1031.  while((*lpString!='\0')&&(*lpString!=':')&&
  1032.        !((*lpString==' ')||(*lpString=='\t'))) lpString++;
  1033.  while((*lpString==' ')||(*lpString=='\t')) *(lpString++)=='\0';
  1034.  if(*lpString!=':')
  1035.  {
  1036.   smtpSendMessage(lpClient, 501, MSG_SYNTAXERROR);
  1037.   return(NULL);
  1038.  }
  1039.  *(lpString++)='\0';
  1040.  while((*lpString==' ')||(*lpString=='\t')) lpString++;
  1041.  if(lstrcmpi(lpTemp, lpWord))
  1042.  {
  1043.   smtpSendMessage(lpClient, 501, MSG_SYNTAXERROR);
  1044.   return(NULL);
  1045.  }
  1046.  DEBUGIT("smtpSkipWord() End");
  1047.  return(lpString);
  1048. } /* smtpSkipWord */
  1049.  
  1050.  
  1051. /* void smtpAppendToFile(LPSMTPCLIENT, LPSTR, LPSTR);
  1052.     Purpose: To copy one file to the end of another.
  1053.     Given:   Pointer to a SMTPCLIENT for error messages,
  1054.              Filename of the file to append to,
  1055.              Filename of the file to append from.
  1056.     Returns: Nothing.
  1057. */
  1058. void smtpAppendToFile(LPSMTPCLIENT lpClient, LPSTR lpTo, LPSTR lpFrom)
  1059. {
  1060.  HFILE hTo, hFrom;
  1061.  char szBuffer[MAXSNDBUFF];
  1062.  int iSize;
  1063.  OFSTRUCT ofToFileStruct,
  1064.           ofFromFileStruct;
  1065.  
  1066.  DEBUGIT("smtpAppendToFile() Begin");
  1067.     // Open the MAIL file for reading
  1068.  hTo=OpenFile(lpTo, (OFSTRUCT FAR *)&ofToFileStruct,
  1069.               OF_WRITE | OF_SHARE_EXCLUSIVE);
  1070.     // Does the main MAIL file exist?
  1071.  if(hTo==HFILE_ERROR)
  1072.  {
  1073.     // No? Create one.
  1074.   hTo=OpenFile(lpTo, (OFSTRUCT FAR *)&ofToFileStruct,
  1075.                OF_CREATE | OF_WRITE | OF_SHARE_EXCLUSIVE);
  1076.     // Serious error!
  1077.   if(hTo==HFILE_ERROR)
  1078.   {
  1079.    smtpSendMessage(lpClient, 503, MSG_MAILOPEN);
  1080.    smtpError(IDS_COULDNTOPEN_S, lpTo);
  1081.    DEBUGIT("smtpAppendToFile() End (File error 1)");
  1082.    return;
  1083.   }
  1084.  }
  1085.  
  1086.     // Open the temporary file
  1087.  hFrom=OpenFile(lpFrom, (OFSTRUCT FAR *)&ofToFileStruct,
  1088.                 OF_READ | OF_SHARE_DENY_WRITE);
  1089.  if(hFrom==HFILE_ERROR)
  1090.  {
  1091.    smtpSendMessage(lpClient, 503, MSG_TEMPOPEN);
  1092.    smtpError(IDS_COULDNTOPEN_S, lpFrom);
  1093.    _lclose(hTo);
  1094.    DEBUGIT("smtpAppendToFile() End (File error 2)");
  1095.    return;
  1096.  }
  1097.  
  1098.     // Seek to the end of the main MAIL file
  1099.  if(_llseek(hTo, 0, 2)==HFILE_ERROR)
  1100.  {
  1101.   smtpSendMessage(lpClient, 503, MSG_SEEKERROR);
  1102.   smtpError(IDS_FILEERROR_S, lpTo);
  1103.   _lclose(hTo);
  1104.   _lclose(hFrom);
  1105.    DEBUGIT("smtpAppendToFile() End (File error 3)");
  1106.   return;
  1107.  }
  1108.  
  1109.     // Copy the temporary file to the end of the MAIL file
  1110.  while(iSize=_lread(hFrom, (LPSTR)szBuffer, sizeof(szBuffer)))
  1111.  {
  1112.   if((iSize==HFILE_ERROR)||
  1113.      (_lwrite(hTo, (LPSTR)szBuffer, iSize)==HFILE_ERROR)) break;
  1114.  }
  1115.     // Close 'em both
  1116.  _lclose(hTo);
  1117.  _lclose(hFrom);
  1118.  
  1119.     // Icon Flag!
  1120.  bMailArrived=TRUE;
  1121.  RedrawWindow(hWndDlg, NULL, NULL, RDW_INTERNALPAINT);
  1122.  
  1123.     // Tell user mail just came
  1124.  MessageBeep(MB_ICONEXCLAMATION);
  1125.  
  1126.     // Wait a bit and check to see if this mail still exists
  1127.  SetTimer(hWndDlg, (UINT)ID_TIMER, (UINT)TIME_CHECK, NULL);
  1128.  
  1129.     // Delete the temporary file
  1130.  if(!lpClient) return;
  1131.  if(lpClient->iMessageType!=CMDSAML)
  1132.  {
  1133.   OpenFile(lpFrom, (OFSTRUCT FAR *)&ofFromFileStruct,
  1134.            OF_DELETE);
  1135.  }
  1136.  DEBUGIT("smtpAppendToFile() End");
  1137.  return;
  1138. } /* smtpAppendToFile() */
  1139.  
  1140.  
  1141. /* BOOL smtpMailCheck(LPSTR);
  1142.     Purpose: To check to see if the main mail file still exists.
  1143.     Given:   Filename of the main file to check for.
  1144.     Returns: Nothing.
  1145.     Other:   Modifies mail flag
  1146. */
  1147. BOOL smtpMailCheck(LPSTR lpFilename)
  1148. {
  1149.  OFSTRUCT ofFile;
  1150.  HICON hIcon;
  1151.  
  1152.  if(OpenFile(lpFilename, (OFSTRUCT FAR *)&ofFile,
  1153.              OF_EXIST | OF_SHARE_COMPAT) != HFILE_ERROR)
  1154.  {
  1155.   bMailArrived=TRUE;
  1156.   hIcon=LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICONFULL));
  1157.  }
  1158.  else
  1159.  {
  1160.   bMailArrived=FALSE;
  1161.   hIcon=LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICONEMPTY));
  1162.  }
  1163.  RedrawWindow(hWndDlg, NULL, NULL, RDW_INTERNALPAINT);
  1164.  SetProp(hWndDlg, "icon", hIcon);
  1165.  return(bMailArrived);
  1166. } /* smtpMailCheck() */
  1167.  
  1168.  
  1169. /* BOOL smtpDisplayFile(LPSMTPCLIENT, LPSTR);
  1170.     Purpose: To display a mail message to the screen for
  1171.              SEND and SAML.
  1172.     Given:   Pointer to a related SMTPCLIENT struct, filename
  1173.     Return:  TRUE if error, FALSE if not.
  1174. */
  1175. BOOL smtpDisplayFile(LPSMTPCLIENT lpClient, LPSTR lpFilename)
  1176. {
  1177.  char szCommand[256];
  1178.  OFSTRUCT ofFile;
  1179.  
  1180.  DEBUGIT("smtpDisplayFile() Begin");
  1181.     // Beep user to tell them mail came.
  1182.  MessageBeep(MB_ICONEXCLAMATION);
  1183.  
  1184.     // "Fork" off a notepad to handle it
  1185.  wsprintf((LPSTR)szCommand, "notepad %s", lpFilename);
  1186.  if(WinExec((LPSTR)szCommand, SW_SHOW)<32)
  1187.  {
  1188.   smtpAppendToFile(lpClient, (LPSTR)szLocalMailPath, lpFilename);
  1189.  }
  1190.  
  1191.     // Delete the temporary file
  1192.  if((lpClient->iMessageType==CMDSAML)||
  1193.     (lpClient->iMessageType==CMDSEND))
  1194.  {
  1195.   OpenFile(lpFilename, (OFSTRUCT FAR *)&ofFile,
  1196.            OF_DELETE);
  1197.  }
  1198.  DEBUGIT("smtpDisplayFile() End");
  1199.  return(FALSE);
  1200. } /* smtpDisplayFile() */
  1201.  
  1202.  
  1203. /* LPSMTPCLIENT smtpAddClient(SOCKET);
  1204.     Purpose: Allocate a client structure and initilize it.
  1205.     Given:   SOCKET of a connection.
  1206.     Returns: A negative number on error, or a
  1207.              valid SMTPCLIENT index into
  1208.              smtpClientsTable
  1209.     Reusability notes:
  1210.              SMTPCLIENT smtpClientsTable;
  1211.              PHASE_INIT,3 MAXBUFF, MAXCLIENTS;
  1212. */
  1213. LPSMTPCLIENT smtpAddClient(SOCKET sSocket)
  1214. {
  1215.  int iRcvSize;
  1216.  int iSizeofRcvSize;
  1217.  HANDLE hInput, hOutput;
  1218.  HCLIENT hClient;
  1219.  LPSTR lpInput, lpOutput;
  1220.  LPSMTPCLIENT lpClient, lpWalker;
  1221.  
  1222.  DEBUGIT("smtpAddClient() Begin");
  1223.     // Find the receiver buffer size
  1224.  iSizeofRcvSize=sizeof(iRcvSize);
  1225.  getsockopt(sSocket, SOL_SOCKET, SO_RCVBUF, (LPSTR)&iRcvSize,
  1226.             (LPINT)&iSizeofRcvSize );
  1227.  
  1228.     // Make sure we can handle a certain size line at a time
  1229.  if(iRcvSize<MAXSNDBUFF) iRcvSize=MAXSNDBUFF;
  1230.  
  1231.     // Make sure we can handle up to 2 buffers at a time
  1232.  iRcvSize=iRcvSize*2;
  1233.  
  1234.     // Allocate the receiver buffer
  1235.  hInput=GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
  1236.                   iRcvSize);
  1237.  if(!hInput) return(NULL);
  1238.  lpInput=GlobalLock(hInput);
  1239.  if(!lpInput)
  1240.  {
  1241.   GlobalFree(hInput);
  1242.   return(NULL);
  1243.  }
  1244.  
  1245.     // Allocate the sending buffer
  1246.  // The size is permanent, we only need dynamic with incoming
  1247.  hOutput=GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
  1248.                   MAXSNDBUFF);
  1249.  if(!hOutput)
  1250.  {
  1251.   GlobalUnlock(hInput);
  1252.   GlobalFree(hInput);
  1253.   return(NULL);
  1254.  }
  1255.  lpOutput=GlobalLock(hOutput);
  1256.  if(!lpOutput)
  1257.  {
  1258.   GlobalFree(hOutput);
  1259.   GlobalUnlock(hInput);
  1260.   GlobalFree(hInput);
  1261.   return(NULL);
  1262.  }
  1263.  
  1264.     // Allocate a SMTPCLIENT element
  1265.  hClient=GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
  1266.                   sizeof(SMTPCLIENT));
  1267.  if(!hClient)
  1268.  {
  1269.   GlobalUnlock(hOutput);
  1270.   GlobalFree(hOutput);
  1271.   GlobalUnlock(hInput);
  1272.   GlobalFree(hInput);
  1273.   return(NULL);
  1274.  }
  1275.  lpClient=(LPSMTPCLIENT)GlobalLock(hClient);
  1276.  if(!lpClient)
  1277.  {
  1278.   GlobalFree(hClient);
  1279.   GlobalUnlock(hOutput);
  1280.   GlobalFree(hOutput);
  1281.   GlobalUnlock(hInput);
  1282.   GlobalFree(hInput);
  1283.   return(NULL);
  1284.  }
  1285.  
  1286.  lpClient->sSocket=sSocket;
  1287.  lpClient->bHaveFrom=FALSE;
  1288.  lpClient->hfFile=HFILE_ERROR;
  1289.  lpClient->hClient=hClient;
  1290.  
  1291.  lpClient->lpOutputBuffer=lpOutput;
  1292.  lpClient->hOutputBuffer=hOutput;
  1293.     // iOutputSize is MAXSNDBUFF
  1294.  lpClient->lpInputBuffer=lpInput;
  1295.  lpClient->hInputBuffer=hInput;
  1296.  lpClient->iInputSize=iRcvSize;
  1297.  
  1298.  lpClient->fifoOutputStart=0;
  1299.  lpClient->fifoOutputStop=0;
  1300.  lpClient->fifoInputStart=0;
  1301.  lpClient->fifoInputStop=0;
  1302.  lpClient->iState=STATE_WAIT_FOR_COMMAND;
  1303.  lpClient->iExtendedFlags=ESMTP_NONE;
  1304.  
  1305.  lpClient->lpNextClient=NULL;
  1306.  lpClient->lpPrevClient=NULL;
  1307.  
  1308.     // If this is the main listening socket, initialize List
  1309.  if(!smtpClientsHead)
  1310.  {
  1311.   smtpClientsHead=lpClient;
  1312.  }
  1313.  else
  1314.  {
  1315.   lpWalker=smtpClientsHead;
  1316.   while(lpWalker->lpNextClient) lpWalker=lpWalker->lpNextClient;
  1317.   lpWalker->lpNextClient=lpClient;  // Add new tail segment
  1318.   lpClient->lpPrevClient=lpWalker;  // Tell tail who's its parent
  1319.  }
  1320.  
  1321.  DEBUGIT("smtpAddClient() End");
  1322.  return(lpClient);
  1323. } /* smtpAddClient */
  1324.  
  1325.  
  1326. /* LPSMTPCLIENT smtpSocketToClient(SOCKET sSocket) */
  1327. LPSMTPCLIENT smtpSocketToClient(SOCKET sSocket)
  1328. {
  1329.  LPSMTPCLIENT lpClient;
  1330.  
  1331.  if((!lpClient)||(sSocket==SOCKET_ERROR)) return(NULL);
  1332.  lpClient=smtpClientsHead;
  1333.  
  1334.  while(lpClient!=NULL)
  1335.  {
  1336.   if(lpClient->sSocket==sSocket) return(lpClient);
  1337.   lpClient=lpClient->lpNextClient;
  1338.  }
  1339.  return(lpClient);
  1340. } /* smtpSocketToClient() */
  1341.  
  1342.  
  1343. /* BOOL smtpDestroyClient(LPSMTPCLIENT);
  1344.     Purpose: To release a SMTPCLIENT structure.
  1345.     Given:   Linked list element pointer
  1346.     Returns: TRUE if error, FALSE if all OK
  1347.     Reusability notes:
  1348. */
  1349. BOOL smtpDestroyClient(LPSMTPCLIENT lpClient)
  1350. {
  1351.  BOOL bLinger = FALSE;
  1352.  LPSMTPCLIENT lpNext, lpPrev;
  1353.  
  1354.  DEBUGIT("smtpDestroyClient() Begin");
  1355.  if(!lpClient) return(TRUE);
  1356.  
  1357.     // This code was removed as "dead" code. The setsockopt() just sets
  1358.     // the SO_LINGER option to what it already should be by default
  1359.     // (thanks Bob (rcq@ftp.com))
  1360. // setsockopt(lpClient->sSocket,
  1361. //            SOL_SOCKET, SO_LINGER, (char FAR *)&bLinger,
  1362. //            sizeof(BOOL));
  1363.     // This shutdown isn't needed either...
  1364. // shutdown(lpClient->sSocket, 2);
  1365.  closesocket(lpClient->sSocket);
  1366.  
  1367.  smtpLog(LOG_HIGH | LOG_TIME, LOG_DISCONNECT_S, (LPSTR)lpClient->szPeer);
  1368.  
  1369.     // Hack Alert! This is a hack, this is only a hack. If this were
  1370.     // real winsock compliant code, it shouldn't have to do this!
  1371.     // But it doesn't hurt, and Lanera seems to need it?
  1372.     // Since this is non-standard, it is now no longer needed - but I
  1373.     // doubt if it will work on Lanera's stack anymore..
  1374.  //if(lpClient!=smtpClientsHead)
  1375.  //{
  1376.  // WSAAsyncSelect(smtpClientsHead->sSocket, hWndMain, NET_ACTIVITY,
  1377.  //                FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE);
  1378.  //}
  1379.  
  1380.     // Is the DATA temporary file still open?
  1381.  if(lpClient->hfFile!=HFILE_ERROR)
  1382.  {
  1383.   _lclose(lpClient->hfFile);
  1384.     // Take it as valid - but don't send any messages
  1385.   smtpAppendToFile(NULL, szLocalMailPath,
  1386.                    lpClient->szFile);
  1387.  }
  1388.  
  1389.     // Patch out THIS segment.
  1390.  lpNext=lpClient->lpNextClient;
  1391.  lpPrev=lpClient->lpPrevClient;
  1392.  if(lpPrev) lpPrev->lpNextClient=lpNext;
  1393.  
  1394.     // Free all of the memory
  1395.  GlobalUnlock(lpClient->hInputBuffer);
  1396.  GlobalFree(lpClient->hInputBuffer);
  1397.  GlobalUnlock(lpClient->hOutputBuffer);
  1398.  GlobalFree(lpClient->hOutputBuffer);
  1399.  GlobalUnlock(lpClient->hClient);
  1400.  GlobalFree(lpClient->hClient);
  1401.  
  1402.  DEBUGIT("smtpDestroyClient() End");
  1403.  return(FALSE);
  1404. } /* smtpDestroyClient */
  1405.  
  1406.  
  1407. /* void smtpSendMessage(LPSMTPCLIENT, int, int, ...);
  1408.     Purpose: To send a resource/reply message.
  1409.     Given:   index into smtpClientsTable
  1410.              SMTP reply number (211, 503)
  1411.              Resource ID of the reply string.
  1412.              ... arguments
  1413.     Returns: Nothing.
  1414.     Other:   If the Resource ID String has a '\n' in it,
  1415.              this routine will send it line at a time.
  1416. */
  1417. void smtpSendMessage(LPSMTPCLIENT lpClient, int SMTPCode, int ResourceID, ...)
  1418. {
  1419.  int iCount;
  1420.  char szString[MAXSNDBUFF];
  1421.  char szLine[MAXSNDBUFF];
  1422.  LPSTR lpArg1, lpArg2, lpArg3;
  1423.  PSTR pStart, pStop;
  1424.  va_list vaArgs;
  1425.  
  1426.  DEBUGIT("smtpSendMessage() Begin");
  1427.  if(!lpClient) return;
  1428.  
  1429.  va_start( vaArgs, ResourceID);
  1430.  
  1431.  if(!LoadString(hInst, ResourceID, (LPSTR)szLine, sizeof(szLine)))
  1432.     return;
  1433.  
  1434.  lpArg1=va_arg(vaArgs, LPSTR);
  1435.  lpArg2=va_arg(vaArgs, LPSTR);
  1436.  lpArg3=va_arg(vaArgs, LPSTR);
  1437.  
  1438.  wsprintf((LPSTR)szString, (LPSTR)szLine, lpArg1, lpArg2, lpArg3);
  1439.  
  1440.  pStart=pStop=szString;
  1441.  do     /* Line loop for embedded '\n's */
  1442.  {
  1443.   while((*pStop!='\0')&&(*pStop!='\n')) pStop++;
  1444.   if((*pStop!='\0'))
  1445.   {
  1446.    *(pStop++)='\0';
  1447.    wsprintf((LPSTR)szLine, "%d-%s", SMTPCode, (LPSTR)pStart);
  1448.    pStart=pStop;
  1449.   }
  1450.   else
  1451.   {
  1452.    wsprintf((LPSTR)szLine, "%d %s", SMTPCode, (LPSTR)pStart);
  1453.   }
  1454.   clientSendLine(lpClient, (LPSTR)szLine, lstrlen((LPSTR)szLine));
  1455.   DEBUGIT((LPSTR)szLine);
  1456.   smtpLog(LOG_HIGH, LOG_SENT_S, (LPCSTR)szLine);
  1457.  } while(*pStop!='\0');
  1458.  DEBUGIT("smtpSendMessage() End");
  1459. } /* smtpSendMessage */
  1460.  
  1461.  
  1462. /* int clientSendLine(LPSMTPCLIENT, LPSTR, int);
  1463.     Purpose: Send 1 line to the caller if it exists.
  1464.     Given:   SMTPCLIENT index, Line pointer,
  1465.              Line size. (for binary "string" sends if needed)
  1466.     Returns: 0 if everything isn't ok.
  1467.              >0 tells the caller how many characters it sent.
  1468.     Reusability requirements:
  1469.              Globals: SMTPCLIENT smtpClientsTable[]
  1470.              Defines: MAXCLIENTS, MAXBUFF
  1471.     Other:   THIS ROUTINE ADDS A CR/LF PAIR!
  1472. */
  1473. int clientSendLine(LPSMTPCLIENT lpClient, LPSTR lpLine, int iLine)
  1474. {
  1475.  LPSTR lpBuffer;
  1476.  int fifoStart;
  1477.  int fifoStop;
  1478.  int fifoWalker;
  1479.  int iDest;
  1480.  
  1481.     /* Catch illegal arguements */
  1482.  if((!lpClient)||(lpLine==NULL)||(iLine==0))
  1483.      return(0);
  1484.  
  1485.     /* Make things easier to deal with */
  1486.  lpBuffer=lpClient->lpOutputBuffer;
  1487.  fifoStart=lpClient->fifoOutputStart;
  1488.  fifoWalker=fifoStart;
  1489.  fifoStop=lpClient->fifoOutputStop;
  1490.  
  1491.     /* Make sure there is enough room - Egad */
  1492.  if(( (fifoStop<fifoStart) &&
  1493.       (((fifoStop+iLine+2)&MAXSNDBUFF)>=fifoStart)
  1494.     )            ||
  1495.     ( (fifoStop>=fifoStart) &&
  1496.       (((fifoStop+iLine+2)/MAXSNDBUFF)==1) &&
  1497.       (((fifoStop+iLine+2)%MAXSNDBUFF)>=fifoStart)
  1498.     ))
  1499.     return(0);
  1500.  
  1501.     /* There is room at the end! Copy it in! */
  1502.  iDest=0;
  1503.  fifoWalker=fifoStop;
  1504.  while(iDest<iLine)
  1505.  {
  1506.   lpBuffer[fifoWalker]=lpLine[iDest];
  1507.   fifoWalker=(fifoWalker+1)%MAXSNDBUFF;
  1508.   iDest++;
  1509.  }
  1510.  lpBuffer[fifoWalker]='\r';      // Append CR on output
  1511.  fifoWalker=(fifoWalker+1)%MAXSNDBUFF;
  1512.  lpBuffer[fifoWalker]='\n';      // Append LF on output
  1513.  fifoWalker=(fifoWalker+1)%MAXSNDBUFF;
  1514.  
  1515.  lpClient->fifoOutputStop=fifoWalker;
  1516.     // This is important
  1517.  netSendData(lpClient);
  1518.  return(iDest);                  // Tell em how many we copied!
  1519. } /* clientSendLine */
  1520.  
  1521.  
  1522. /* int clientReceiveLine(LPSMTPCLIENT, LPSTR, int);
  1523.     Purpose: Receive 1 line for the caller if it exists.
  1524.     Given:   SMTPCLIENT pointer, Line buffer pointer,
  1525.              Line buffer size.
  1526.     Returns: -1 if no string found in buffer
  1527.              0 if just CR or NL
  1528.              >0 tells the caller how many characters it was.
  1529.     Reusability requirements:
  1530.              None!
  1531.     Notes:   This routines takes into account backspaces,
  1532.              deletes, multiple CRs and LFs.
  1533. */
  1534. int clientReceiveLine(LPSMTPCLIENT lpClient, LPSTR lpLine, int iLine)
  1535. {
  1536.  LPSTR lpBuffer;
  1537.  int iCount;
  1538.  int fifoStart;
  1539.  int fifoStop;
  1540.  int fifoWalker;
  1541.  int iDest;
  1542.  int iMax;
  1543.  
  1544.  if((!lpClient)||(lpLine==NULL)||(iLine==0))
  1545.      return(-1);
  1546.  
  1547.      /* Make things easier to deal with */
  1548.  lpBuffer=lpClient->lpInputBuffer;
  1549.  fifoStart=lpClient->fifoInputStart;
  1550.  fifoWalker=fifoStart;
  1551.  fifoStop=lpClient->fifoInputStop;
  1552.  iMax=lpClient->iInputSize;
  1553.  
  1554.  if(fifoStart==fifoStop) return(-1);
  1555.  
  1556.     /* Search buffer for a LF or CR BEFORE the end of the buffer! */
  1557.  while((lpBuffer[fifoWalker]!='\n')&&
  1558.        (lpBuffer[fifoWalker]!='\r'))
  1559.  {
  1560.   fifoWalker=(fifoWalker+1)%iMax;
  1561.   if(fifoWalker==fifoStop)
  1562.     return(-1);
  1563.  }
  1564.  
  1565.     /* We found the end of a string! Copy it out. */
  1566.  *lpLine='\0';
  1567.  
  1568.  iDest=0;
  1569.  fifoWalker=fifoStart;
  1570.  while((lpBuffer[fifoWalker]!='\n')&&
  1571.        (lpBuffer[fifoWalker]!='\r'))
  1572.  {
  1573.   if((lpBuffer[fifoWalker]=='\b')||     // Backspace (^H)
  1574.      (lpBuffer[fifoWalker]=='\177'))    // Delete    (^?)
  1575.   { // Interactive User is talking to us (and making mistakes)
  1576.    if((--iDest)<0) iDest=0;             // Backup if we can
  1577.    fifoWalker=(fifoWalker+1)%iMax;      // Step over ^H or ^?
  1578.    continue;                            // for ^H^H... case
  1579.   }
  1580.   lpLine[iDest]=lpBuffer[fifoWalker];
  1581.   fifoWalker=(fifoWalker+1)%iMax;
  1582.   iDest++;
  1583.   if(iDest>=iLine)
  1584.      return(-1);  // Not enough string space!!!
  1585.  }
  1586.  lpLine[iDest]='\0';
  1587.  
  1588.                                // Step past the '\r'
  1589.  if((fifoWalker!=fifoStop)&&
  1590.     (lpBuffer[fifoWalker]=='\r')) fifoWalker=(fifoWalker+1)%iMax;
  1591.  
  1592.                                // Step past the '\n'
  1593.  if((fifoWalker!=fifoStop)&&
  1594.     (lpBuffer[fifoWalker]=='\n')) fifoWalker=(fifoWalker+1)%iMax;
  1595.  
  1596.  lpClient->fifoInputStart=fifoWalker;
  1597.  smtpLog(LOG_HIGH, LOG_RECEIVED_S, (LPCSTR)lpLine);
  1598.  return(iDest);              // Tell em how many we copied!
  1599. } /* clientReceiveLine */
  1600.  
  1601.  
  1602. /* int clientReceiveBlock(int, LPSTR, int);
  1603.     Purpose: Receive entire FIFO block for the caller if it exists.
  1604.     Given:   SMTPCLIENT index, Block buffer pointer,
  1605.              Block buffer size.
  1606.     Returns: 0 if everything isn't ok. (no characters waiting)
  1607.              >0 tells the caller how many characters it was.
  1608.     Reusability requirements:
  1609.              Globals: SMTPCLIENT smtpClientsTable[]
  1610.              Defines: MAXCLIENTS, MAXBUFF
  1611.     Notes:   This kind of defeats the idea of FIFO, but it does
  1612.              allow for 8 bit binary transfers.
  1613.              Since it was easier to implement 8BITMIME termination
  1614.              in here, I have left it so. This is not good design.
  1615. */
  1616. int clientReceiveBlock(LPSMTPCLIENT lpClient, LPSTR lpLine, int iLine)
  1617. {
  1618.  LPSTR lpBuffer;
  1619.  int fifoStart;
  1620.  int fifoStop;
  1621.  int fifoWalker;
  1622.  int iDest;
  1623.  int iMax;
  1624.  
  1625.  if((!lpClient)||(lpLine==NULL)||(iLine==0))
  1626.      return(0);
  1627.  
  1628.     // Make things easier to deal with
  1629.  lpBuffer=lpClient->lpInputBuffer;
  1630.  fifoStart=lpClient->fifoInputStart;
  1631.  fifoStop=lpClient->fifoInputStop;
  1632.  iMax=lpClient->iInputSize;
  1633.  
  1634.  if(fifoStart==fifoStop) return(0);
  1635.  
  1636.  iDest=0;
  1637.  fifoWalker=fifoStart;
  1638.  while(fifoWalker!=fifoStop)
  1639.  {
  1640.   if(lpBuffer[fifoWalker]=='.')
  1641.   {
  1642.     // Check for presence of, and validity of "\r\n.\r\n"
  1643.     // Elegant, yet ugly
  1644.     // Possible bug: What if the above sequence comes split?
  1645.    if(((((fifoWalker-2)%iMax) != fifoStart) &&
  1646.        (lpBuffer[(fifoWalker-2)%iMax]=='\r'))
  1647.     &&((((fifoWalker-1)%iMax) != fifoStart) &&
  1648.        (lpBuffer[(fifoWalker-1)%iMax]=='\n'))
  1649.     &&((((fifoWalker+1)%iMax) != fifoStop) &&
  1650.        (lpBuffer[(fifoWalker+1)%iMax]=='\r'))
  1651.     &&((((fifoWalker+2)%iMax) != fifoStop) &&
  1652.        (lpBuffer[(fifoWalker+2)%iMax]=='\n'))
  1653.      )
  1654.    {    // End of message
  1655.      if(lpClient->hfFile!=HFILE_ERROR)
  1656.      {
  1657.              _lclose(lpClient->hfFile);
  1658.      }
  1659.      lpClient->hfFile=HFILE_ERROR;
  1660.      smtpAppendToFile(lpClient, szLocalMailPath,
  1661.                       lpClient->szFile);
  1662.      lpClient->iState=STATE_WAIT_FOR_COMMAND;
  1663.      smtpSendMessage(lpClient, 250, MSG_OK);
  1664.      fifoWalker=(fifoWalker+2)%iMax;
  1665.      break;
  1666.    }
  1667.   } // Pass EVERYTHING else through.
  1668.   lpLine[iDest]=lpBuffer[fifoWalker];
  1669.   fifoWalker=(fifoWalker+1)%iMax;
  1670.   iDest++;
  1671.  }
  1672.  lpLine[iDest]='\0';    // Zero terminate it, for luck
  1673.  
  1674.  lpClient->fifoInputStart=fifoWalker;
  1675.  
  1676.  smtpLog(LOG_HIGH, LOG_RECEIVED_S, (LPCSTR)lpLine);
  1677.  return(iDest);              // Tell em how many we copied!
  1678. } /* clientReceiveBlock */
  1679.  
  1680. /**** End of WSMTPSRV.C ****/
  1681.